package main

import (
	"flag"
	"fmt"
	"github.com/hashicorp/consul/api"
	"github.com/satori/go.uuid"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"
	"net"
	"os"
	"os/signal"
	"sale_system/userop_srv/global"
	"sale_system/userop_srv/utils"
	"syscall"

	"sale_system/userop_srv/handler"
	"sale_system/userop_srv/initialize"
	"sale_system/userop_srv/proto"
)

// 注意如果连接不上数据库：需要打开虚拟机，并输入
// docker start mysql-server
// docker run  -p 6379:6379 -d redis:latest redis-server
// user-service 8899  user-web-8080
func main() {

	initialize.InitLogger()
	initialize.InitConfig() // 注意顺序：一定要先初始化配置文件

	initialize.InitDB()
	zap.S().Info(global.ServerConfig)

	// 命令行参数获取ip和端口号
	ip := flag.String("ip", global.ServerConfig.Host, "ip 地址") // 192.168.56.103 就是宿主机也就是我的电脑的 127.0.0.1
	port := flag.Int("port", 8899, "port 端口号")                 // 改为0表示使用系统的，你可以固定8899等端口号
	flag.Parse()

	if *port == 0 { // 如果没有在命令行参数提供端口号，就使用系统分配的
		*port, _ = utils.GetFreePort()
	}
	zap.S().Infof("server ip: %s, port: %d", *ip, *port)

	server := grpc.NewServer()
	proto.RegisterAddressServer(server, &handler.AddressServer{})
	proto.RegisterMessageServer(server, &handler.MessageServer{})
	proto.RegisterUserFavServer(server, &handler.UserFavServer{})

	// 监听TCP链接
	lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", *ip, *port))
	if err != nil {
		panic("failed to listen, " + err.Error())
	}

	// 进行服务健康检查
	grpc_health_v1.RegisterHealthServer(server, health.NewServer())

	// 进行服务注册
	cfg := api.DefaultConfig()
	cfg.Address = fmt.Sprintf("http://%s:%d", global.ServerConfig.ConsulInfo.Host, global.ServerConfig.ConsulInfo.Port) // consul的地址

	clientConsul, err := api.NewClient(cfg)
	if err != nil {
		panic(err)
	}

	uuidSrv := fmt.Sprintf("%s", uuid.NewV4())
	// 定义注册对象 -
	registration := new(api.AgentServiceRegistration)
	registration.Name = global.ServerConfig.Name
	registration.ID = uuidSrv // 注意启动多个实例并维护在Consul需要ID不同
	registration.Port = *port
	registration.Tags = global.ServerConfig.Tags
	registration.Address = global.ServerConfig.Host

	// 生成http检查对象
	check := &api.AgentServiceCheck{
		GRPC:                           fmt.Sprintf("%s:%d", *ip, *port),
		Timeout:                        "5s",
		Interval:                       "60s", // 5s进行一次检测
		DeregisterCriticalServiceAfter: "10s",
	}

	registration.Check = check

	// 进行服务注册
	err = clientConsul.Agent().ServiceRegister(registration)

	if err != nil {
		panic(err)
	}

	go func() {
		err = server.Serve(lis)
		if err != nil {
			panic("failed to serve grpc, " + err.Error())
		}
	}()

	// 优雅退出
	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

	<-quit // 阻塞读取直到，读取到退出信息
	if err = clientConsul.Agent().ServiceDeregister(registration.ID); err != nil {
		zap.S().Info("注销失败")
		return
	}
	zap.S().Infof("注销成功")

}
